package cvm

import (
	"context"
	"strings"

	"gitee.com/go-course/go8/projects/devcloud/cmdb/apps/host"
	"gitee.com/go-course/go8/projects/devcloud/cmdb/apps/resource"
	"gitee.com/go-course/go8/projects/devcloud/cmdb/provider/txyun/mapping"
	"gitee.com/go-course/go8/projects/devcloud/cmdb/utils"
	"github.com/alibabacloud-go/tea/tea"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"

	cvm "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cvm/v20170312"
)

func NewDescribeInstancesRequest() *cvm.DescribeInstancesRequest {
	return cvm.NewDescribeInstancesRequest()
}

// 带分页功能的查询
// 要把所有资源全部同步下来, 需要客户端拉起所有页面的实例数据
// 我们需要实现一个带分页查询功能的一个客户端, 这个客户端能把所有的页面都查询完
// 云商由速率限制? 比如每秒请求10页数据, 可以超过速率限制
// pager里面是需要控制 云商接口的访问频率
func (o *CVMOperator) PageCvmQuery() *CvmPager {
	return NewCvmPager(o, &CvmPagerRequest{PageSize: 20, PageNumber: 1})
}

// 查询cvm列表(只拉去一页), 查询完成后转换为标准的Host对象
// https://console.cloud.tencent.com/api/explorer?Product=cvm&Version=2017-03-12&Action=DescribeInstances
func (o *CVMOperator) QueryCvm(ctx context.Context, req *cvm.DescribeInstancesRequest) (*host.HostSet, error) {
	// 1.调用cvm客户端 查询cvm实例列表
	// 返回的resp是一个DescribeInstancesResponse的实例，与请求对象对应
	response, err := o.client.DescribeInstances(req)
	if _, ok := err.(*errors.TencentCloudSDKError); ok {
		return nil, err
	}

	// 2.转换为cdmb Host对象
	set := o.transferSet(response.Response.InstanceSet)
	return set, nil
}

func (o *CVMOperator) transferSet(items []*cvm.Instance) *host.HostSet {
	set := host.NewHostSet()
	for i := range items {
		set.Add(o.transferOne(items[i]))
	}
	return set
}

func (o *CVMOperator) transferOne(ins *cvm.Instance) *host.Host {
	r := host.NewDefaultHost()
	b := r.Resource.Meta
	b.CreateAt = utils.ParseDefaultSecondTime(utils.PtrStrV(ins.CreatedTime))
	b.ResourceId = utils.PtrStrV(ins.InstanceId)
	b.SerialNumber = utils.PtrStrV(ins.Uuid)

	i := r.Resource.Spec
	i.Vendor = resource.VENDOR_TENCENT
	i.Region = o.client.GetRegion()
	i.Zone = utils.PtrStrV(ins.Placement.Zone)
	i.Owner = o.account
	i.ExpireAt = utils.ParseDefaultSecondTime(utils.PtrStrV(ins.ExpiredTime))
	i.Type = utils.PtrStrV(ins.InstanceType)
	i.Name = utils.PtrStrV(ins.InstanceName)

	if ins.InternetAccessible != nil {
		i.BandWidth = int32(tea.Int64Value(ins.InternetAccessible.InternetMaxBandwidthOut))
	}
	i.Cpu = int32(utils.PtrInt64(ins.CPU))
	i.Memory = int32(utils.PtrInt64(ins.Memory))

	pm := mapping.PrasePayMode(tea.StringValue(ins.InstanceChargeType))
	r.Resource.Cost.PayMode = &pm
	r.Resource.Status.PublicIp = strings.Join(utils.SlicePtrStrv(ins.PublicIpAddresses), ",")
	r.Resource.Status.PrivateIp = strings.Join(utils.SlicePtrStrv(ins.PrivateIpAddresses), ",")
	r.Resource.Status.Phase = utils.PtrStrV(ins.InstanceState)

	r.Resource.Tags = transferTags(ins.Tags)

	r.Spec.OsName = utils.PtrStrV(ins.OsName)

	r.Spec.ImageId = utils.PtrStrV(ins.ImageId)
	return r
}

func transferTags(tags []*cvm.Tag) (ret []*resource.Tag) {
	for i := range tags {
		ret = append(ret, resource.NewGroupTag(
			utils.PtrStrV(tags[i].Key),
			utils.PtrStrV(tags[i].Value)),
		)
	}
	return
}
